package chap_07;

import org.junit.jupiter.api.Test;

import java.util.function.Function;
import java.util.stream.LongStream;
import java.util.stream.Stream;

/**
 * @ClassName Run_01
 * @Discription 并行流
 * @Author lianming.zhang
 * @Date 2018-11-24 10:06
 * @Version 1.0
 **/
public class Run_01 {

    public static long sequentialSum(long n) {
        return Stream.iterate(1L, i -> i + 1).limit(n).reduce(0L, Long::sum);

    }

    public static long iterativeSum(long n) {
        long result = 0;
        for (long i = 1L; i <= n; i++) {
            result += i;
        }
        return result;
    }

    public static long parallelSum(long n) {
        return Stream.iterate(1L, i -> i + 1).limit(n).parallel().reduce(0L, Long::sum);
    }

    public static long parallelNoBoxSum(long n) {
        return LongStream.iterate(1L, i -> i + 1).limit(n).parallel().reduce(0L, Long::sum);
    }

    public static long rangedSum(long n) {
        return LongStream.rangeClosed(1, n).reduce(0L, Long::sum);
    }

    public static long rangedParallelSum(long n) {
        return LongStream.rangeClosed(1, n).parallel().reduce(0L, Long::sum);
    }

    /**
     * 对long值进行10次计算，返回时间最短的一次
     *
     * @param adder
     * @param n
     * @return
     */
    public long measureSumPerf(Function<Long, Long> adder, long n) {
        long fastest = Long.MAX_VALUE;
        for (int i = 0; i < 10; i++) {
            long start = System.nanoTime();
            long sum = adder.apply(n);
            long duration = (System.nanoTime() - start) / 1_000_000;
            System.out.println("Result: " + sum);
            if (duration < fastest) {
                fastest = duration;
            }
        }
        return fastest;

    }

    /**
     * 顺序累加器
     * 约 92 mesec
     * 包含拆装箱成本
     */
    @Test
    public void test01() {
        System.out.println("Sequential sum done in:" + measureSumPerf(Run_01::sequentialSum, 10_000_000) + " msecs");
    }

    /**
     * 传统for循环
     * 约 3 mesec
     * 不包含拆装箱成本
     */
    @Test
    public void test02() {
        System.out.println("Iterative sum done in:" + measureSumPerf(Run_01::iterativeSum, 10_000_000) + " msecs");
    }

    /**
     * 并行流
     * 约 205 mesec
     * 包含拆装箱成本，并且iterator很难并行执行
     */
    @Test
    public void test03() {
        System.out.println("Parallel sum done in: " + measureSumPerf(Run_01::parallelSum, 10_000_000) + " msecs");
    }

    /**
     * 并行流-不进行拆装箱
     * 约 79 mesec
     * 包含拆装箱成本，并且iterator很难并行执行
     */
    @Test
    public void test04() {
        System.out.println("Parallel sum done in: " + measureSumPerf(Run_01::parallelNoBoxSum, 10_000_000) + " msecs");
    }

    /**
     * 无拆装箱成本,非并行
     * 约 6 mesec
     */
    @Test
    public void test05() {
        System.out.println("Ranged sum done in: " + measureSumPerf(Run_01::rangedSum, 10_000_000) + " msecs");
    }

    /**
     * 无拆装箱成本,并行
     * 约 2 mesec
     */
    @Test
    public void test06() {
        System.out.println("Ranged sum done in: " + measureSumPerf(Run_01::rangedParallelSum, 10_000_000) + " msecs");
    }
}
